package com.tg.demo.snowflake.service;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.tg.demo.snowflake.config.SnowflakeProperties;
import com.tg.demo.snowflake.beatheart.SnowflakeBeatHeart;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * @author Rubble
 * Created on 2020/5/23
 */
@Slf4j
@Service
public class SnowflakeRegisterService {

    @Autowired
    private RedisTemplate redisTemplate;


    @Value("${spring.application.name}")
    private String applicationName;


//    private static Snowflake snowflake;

    @Autowired
    private SnowflakeProperties snowflakeProperties;

    private static final int MAX_VALUE = 1024;

    private static final int MAX_WORKER_ID = 31;

    public static final int EXPIRE_TIME = 100;


    @PostConstruct
    public void postInit(){

        registerWorker();

        SnowflakeBeatHeart snowflakeBeatHeart = new SnowflakeBeatHeart(redisTemplate,snowflakeProperties,this);
        snowflakeBeatHeart.startSchedule();
    }


    public void resetWorker(){
        snowflakeProperties.setUuid("");
        IdGeneratorUtil.setSnowflake(null);
    }

    public void registerWorker(){
        resetWorker();
        String uuid = IdUtil.simpleUUID();
        String prefix =  "sw:"+applicationName+":";
        String snowflakeKey = "";
        int val = 0;
        Boolean success = false;
        while(true){
            // 尝试对 0-1023的值进行锁定
            for (int i = 0; i <MAX_VALUE ; i++) {
                snowflakeKey = prefix + i;
                success = redisTemplate.opsForValue().setIfAbsent(snowflakeKey, uuid, EXPIRE_TIME, TimeUnit.SECONDS);
                if(success){
                    val = i;
                    break;
                }
            }

            if(success){
                break;
            }
            try {
                TimeUnit.MICROSECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        int workId = val;
        int dataCenterId = 0;
        if(val> MAX_WORKER_ID){
            workId = val & 31;
            dataCenterId = val>>5;
        }
        log.info("============== WorkerId has registered. val: {} workerId: {} dataCenterId: {} uuid: {}", val, workId, dataCenterId,uuid);

        snowflakeProperties.setUuid(uuid);
        snowflakeProperties.setSnowflakeKey(snowflakeKey);
        snowflakeProperties.setWorkerId(workId);
        snowflakeProperties.setDataCenterId(dataCenterId);
        IdGeneratorUtil.setSnowflake( IdUtil.createSnowflake(workId,dataCenterId));

    }

}
